﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SIEGate.Core.MessageBusses
{
    internal class RoutingTablesMessageBusProxy : IMessageBusProxy
    {
        private RoutingTablesMessageBus m_messageBus;
        private ConcurrentQueue<IMeasurement> m_measurementQueue;

        public RoutingTablesMessageBusProxy(RoutingTablesMessageBus routingTablesMessageBus)
        {
            m_messageBus = routingTablesMessageBus;
            m_measurementQueue = new ConcurrentQueue<IMeasurement>();
            Subscribed = new HashSet<Guid>();
            Published = new HashSet<Guid>();
            ActivePubs = new HashSet<Guid>();
        }

        public ISet<Guid> Subscribed
        {
            get;
            private set;
        }

        public ISet<Guid> Published
        {
            get;
            private set;
        }

        public ISet<Guid> ActivePubs
        {
            get;
            private set;
        }

        public void Subscribe(ISet<Guid> neededMessages)
        {
            foreach (Guid message in neededMessages)
                m_messageBus.RegisterConsumer(message, this);

            Subscribed.UnionWith(neededMessages);
        }

        public void Publish(ISet<Guid> providedMessages)
        {
            foreach (Guid message in providedMessages)
                m_messageBus.RegisterProducer(message, this);

            Published.UnionWith(providedMessages);
        }

        public void UnSubscribe(ISet<Guid> toRemove)
        {
            foreach (Guid message in toRemove)
                m_messageBus.UnregisterConsumer(message, this);
        }

        public void UnPublish(ISet<Guid> toRemove)
        {
            foreach (Guid message in toRemove)
                m_messageBus.UnregisterProducer(message, this);
        }

        public void Send(params IMeasurement[] m)
        {
            m_messageBus.RouteMeasurements(this, m);
        }

        public IMeasurement[] Recv(int max = 0)
        {
            List<IMeasurement> dequeuedMeasurements = new List<IMeasurement>();
            IMeasurement dequeuedMeasurement;
            int count = 0;

            while (m_measurementQueue.TryDequeue(out dequeuedMeasurement) && (count < max || max == 0))
            {
                dequeuedMeasurements.Add(dequeuedMeasurement);
                count++;
            }

            return dequeuedMeasurements.ToArray();
        }

        internal void Enqueue(IMeasurement measurement)
        {
            m_measurementQueue.Enqueue(measurement);
        }

        internal void OnStartSubscription(Guid sid)
        {
            ActivePubs.Add(sid);

            if ((object)StartSubscription != null)
                StartSubscription(this, new MessageBusSubscriptionEventArgs(sid));
        }

        internal void OnEndSubscription(Guid sid)
        {
            ActivePubs.Remove(sid);

            if ((object)EndSubscription != null)
                EndSubscription(this, new MessageBusSubscriptionEventArgs(sid));
        }

        public event EventHandler<MessageBusSubscriptionEventArgs> StartSubscription;
        public event EventHandler<MessageBusSubscriptionEventArgs> EndSubscription;
    }
}
